package jna;

import com.sun.jna.*;
import com.sun.jna.platform.win32.*;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import org.opencv.core.Mat;

import java.io.UnsupportedEncodingException;

import static com.sun.jna.Pointer.NULL;
import static com.sun.jna.platform.win32.GL.GL_VERSION;
import static com.sun.jna.platform.win32.WinGDI.*;
import static com.sun.jna.platform.win32.WinUser.WM_QUIT;
import static org.opencv.core.Core.flip;
import static org.opencv.imgcodecs.Imgcodecs.imread;


public class CWindow {

    private static final int GL_COLOR_BUFFER_BIT = 0x00004000;
    private static final int GL_TRIANGLES = 0x0004;
    private static final int PM_REMOVE = 0x0001;

    public interface WUser extends User32 {
        WUser INSTANCE = (WUser) Native.load("user32", WUser.class, W32APIOptions.DEFAULT_OPTIONS);

        HDC BeginPaint(
                HWND hwnd,
                PAINTSTRUCT lpPaint
        );

        BOOL EndPaint(
                HWND hwnd,
                PAINTSTRUCT lpPaint
        );

    }

    public interface WGDI extends StdCallLibrary {

        WGDI INSTANCE = (WGDI) Native.load("gdi32full", WGDI.class, W32APIOptions.DEFAULT_OPTIONS);

        WinDef.HBRUSH CreateHatchBrush(int fnStyle, int clrref);

        WinDef.BOOL Rectangle(WinDef.HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);

        int GetTextCharset(WinDef.HDC hdc);

        WinDef.BOOL SetPixelFormat(WinDef.HDC hdc, int format, WinGDI.PIXELFORMATDESCRIPTOR ppfd);

        int ChoosePixelFormat(
                WinDef.HDC hdc,
                PIXELFORMATDESCRIPTOR ppfd
        );

        WinDef.BOOL SwapBuffers(WinDef.HDC hdc);

    }

    public interface GL extends StdCallLibrary {
        GL INSTANCE = (GL) Native.load("opengl32", GL.class, W32APIOptions.DEFAULT_OPTIONS);

        Pointer glGetString(int name);

        void glViewport(int x, int y, int width, int height);

        WinDef.HGLRC wglCreateContext(WinDef.HDC hdc);

        WinDef.HDC wglGetCurrentDC();

        WinDef.BOOL wglMakeCurrent(WinDef.HDC hdc, WinDef.HGLRC hglrc);

        void glClearColor(float red, float green, float blue, float alpha);

        void glClear(int mask);

        void glPushMatrix();

        void glRotatef(float angle, float x, float y, float z);

        void glBegin(int mask);

        void glColor3f(float red, float green, float blue);

        void glVertex2f(float red, float green);

        void glEnd();

        void glPopMatrix();

        WinDef.BOOL wglSwapBuffers(WinDef.HDC hdc);

        void glDrawPixels (int width, int height, int format, int type,  Pointer pixels);

    }

    public interface GdiPlus extends StdCallLibrary {
        GdiPlus INSTANCE = (GdiPlus) Native.load("GdiPlus", GdiPlus.class, W32APIOptions.DEFAULT_OPTIONS);


    }


    @Structure.FieldOrder(value = {"hdc", "fErase", "rcPaint", "fRestore", "fIncUpdate", "rgbReserved"})
    public class PAINTSTRUCT extends Structure {
        public WinDef.HDC hdc;
        public WinDef.BOOL fErase;
        public WinDef.RECT rcPaint;
        public WinDef.BOOL fRestore;
        public WinDef.BOOL fIncUpdate;
        public WinDef.BYTE[] rgbReserved = new WinDef.BYTE[32];


        public PAINTSTRUCT() {
        }
    }

    public static int getRGB(int r, int g, int b) {
        int rgb = r + g * 256 + b * 255 * 256;
        return rgb;
    }

    public static void main(String[] args) {
        new CWindow().test();
    }

    public CWindow() {
    }

    WinDef.HDC EnableOpenGL(WinDef.HWND hWnd) {
        WinGDI.PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR();
        int format;

        // get the device context (DC)
        WinDef.HDC hDC = User32.INSTANCE.GetDC(hWnd);

        // set the pixel format for the DC
//        ZeroMemory( pfd, sizeof( pfd ) );
//        pfd.nSize = sizeof( pfd );
        pfd.nSize = 2048;
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 24;
        pfd.cDepthBits = 16;
        pfd.iLayerType = PFD_MAIN_PLANE;
        format = WGDI.INSTANCE.ChoosePixelFormat(hDC, pfd);
        WinDef.BOOL ok = WGDI.INSTANCE.SetPixelFormat(hDC, format, pfd);

        // create and enable the render context (RC)
        WinDef.HGLRC hRC = GL.INSTANCE.wglCreateContext(hDC);
        GL.INSTANCE.wglMakeCurrent(hDC, hRC);

        System.out.println(ok.booleanValue());
//        System.err.println(hDC);
//        System.err.println(hRC);

        return hDC;
    }

    float theta = 0.0f;

    class WindowProc implements Callback {
        public WinDef.LRESULT callback(WinDef.HWND hwnd, WinDef.UINT uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) throws UnsupportedEncodingException {



//            //第 3）步：获取HDC，并随意设置一个空像素格式
//            WinDef.HDC hDC = User32.INSTANCE.GetDC(hwnd);
//            WinGDI.PIXELFORMATDESCRIPTOR pfd = new WinGDI.PIXELFORMATDESCRIPTOR();
//            WGDI.INSTANCE.SetPixelFormat(hDC, 1, pfd);
//
////第 4）步：创建OpenGL环境
//            WinDef.HGLRC
//                    hRC = GL.INSTANCE.wglCreateContext(hDC);
////第 5）步：绑定HDC与HRC
//
//            GL.INSTANCE.wglMakeCurrent(hDC, hRC);
//
//            Pointer s = GL.INSTANCE.glGetString(GL_VERSION);//获取OpenGL版本字符串
//            System.out.println(s.getString(100));


            switch (uMsg.intValue()) {
                case WinUser.WM_CLOSE:
                    User32.INSTANCE.PostQuitMessage(0);
                    break;
                case WinUser.WM_PAINT: {

//                    PAINTSTRUCT ps = new PAINTSTRUCT();
//                    WinDef.HDC hdc = WUser.INSTANCE.BeginPaint(hwnd, ps);
//
//                    WinDef.HBRUSH hBrush = WGDI.INSTANCE.CreateHatchBrush(2, getRGB(255, 100, 100));
//                    WinNT.HANDLE hOldBrush = GDI32.INSTANCE.SelectObject(hdc, hBrush);
//
//                    WGDI.INSTANCE.Rectangle(hdc, 50, 50, 200, 100);
//
//                    GDI32.INSTANCE.SelectObject(hdc, hOldBrush);
//                    GDI32.INSTANCE.DeleteObject(hBrush);
//
//
//                    int i = WGDI.INSTANCE.GetTextCharset(hdc);
//                    System.out.println(i);
//
//                    GL.INSTANCE.glViewport(100, 100, 200, 200);
//
////                    IntByReference intByReference = new IntByReference(20);
////                    WinDef.CHARByReference s = GL.INSTANCE.glGetString(intByReference);
////                    System.out.println(s);
//
//                    WinDef.HGLRC hrc = GL.INSTANCE.wglCreateContext(hdc);
//                    System.out.println(hrc);
//
//                    WUser.INSTANCE.EndPaint(hwnd, ps);




                }
                break;


            }
            return User32.INSTANCE.DefWindowProc(hwnd, uMsg.intValue(), wParam, lParam);
        }
    }
    public void Render(WinDef.HDC hDC){
        GL.INSTANCE.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

        GL.INSTANCE.glClear(GL_COLOR_BUFFER_BIT);

        GL.INSTANCE.glPushMatrix();
        GL.INSTANCE.glRotatef(theta, 0.0f, 0.0f, 1.0f);
        GL.INSTANCE.glBegin(GL_TRIANGLES);
        GL.INSTANCE.glColor3f(1.0f, 0.0f, 0.0f);
        GL.INSTANCE.glVertex2f(0.0f, 1.0f);
        GL.INSTANCE.glColor3f(0.0f, 1.0f, 0.0f);
        GL.INSTANCE.glVertex2f(0.87f, -0.5f);
        GL.INSTANCE.glColor3f(0.0f, 0.0f, 1.0f);
        GL.INSTANCE.glVertex2f(-0.87f, -0.5f);
        GL.INSTANCE.glEnd();
        GL.INSTANCE.glPopMatrix();

//                    WGDI.INSTANCE.SwapBuffers(hDC);

        GL.INSTANCE.wglSwapBuffers(hDC);

        theta += 1.0f;
    }

    public boolean test() {
        String wndClassName = "窗口注册名称";
        String wndTitle = "窗口标题";

        WinDef.HINSTANCE hInstance = null;
        WinUser.WNDCLASSEX wndClassEx = new WinUser.WNDCLASSEX();
        wndClassEx.lpfnWndProc = new WindowProc();
        wndClassEx.cbClsExtra = 0;
        wndClassEx.cbWndExtra = 0;
        wndClassEx.style = 1 | 2;
        wndClassEx.lpszClassName = wndClassName;
        wndClassEx.hInstance = hInstance;
        wndClassEx.hCursor = null;
        wndClassEx.hIcon = null;
        wndClassEx.hbrBackground = null;
        wndClassEx.lpszMenuName = null;


        if (User32.INSTANCE.RegisterClassEx(wndClassEx).intValue() == 0) {
            System.out.println("register window failed!");
            System.out.println("" + Kernel32.INSTANCE.GetLastError() + "\n" + Kernel32Util.getLastErrorMessage());
            return false;
        }

        WinDef.HWND hWnd = User32Util.createWindowEx(0, wndClassName, wndTitle, WinUser.WS_OVERLAPPEDWINDOW,
                100, 100, 500, 400, null, null, hInstance, null);
        if (hWnd == null) {
            System.out.println("create window failed!");
            System.out.println("" + Kernel32.INSTANCE.GetLastError() + "\n" + Kernel32Util.getLastErrorMessage());
            return false;
        }
        User32.INSTANCE.ShowWindow(hWnd, WinUser.SW_SHOWNORMAL);
        User32.INSTANCE.UpdateWindow(hWnd);

//        WinUser.MSG msg = new WinUser.MSG();
//        while (User32.INSTANCE.GetMessage(msg, hWnd, 0, 0) != 0) {
//            User32.INSTANCE.TranslateMessage(msg);
//            User32.INSTANCE.DispatchMessage(msg);
//        }
        WinDef.HDC hDC = EnableOpenGL(hWnd);

        //OpenCV读取图像
        Mat I = imread("img.jpg");
    //设置长宽
        int width = I.cols();
        int height = I.rows();
//设置图像指针
        Pointer pixels;

        //CV图像翻转
        flip(I, I, 0);

        //设置指针长度
        int pixellength = width*height * 3;
        //开辟指针空间
        pixels = new GLubyte[pixellength];

        //图像指针复制
        memcpy(pixels, I.data, pixellength*sizeof(char));




        WinUser.MSG msg = new WinUser.MSG();
        while (true) {
            if (User32.INSTANCE.PeekMessage(msg, hWnd, 0, 0, PM_REMOVE)) {
                if (msg.message == WM_QUIT) {
                    break;
                }
                User32.INSTANCE.TranslateMessage(msg);
                User32.INSTANCE.DispatchMessage(msg);
            } else {
                Render(hDC);
            }
        }

        return true;
    }
}